package uk.ac.ebi.velvet.exec.impl;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.ebi.curtain.utils.io.impl.FileIO;
import uk.ac.ebi.velvet.VelvetUncheckedException;
import uk.ac.ebi.velvet.exec.ProcessorService;
import uk.ac.ebi.velvet.exec.RuntimeExec;

public abstract class AbstractExec {

	private Log log = LogFactory.getLog(this.getClass());
	public AbstractExec() {
		super();
	}

	protected int exec(File baseDir, String[] cmdArr, File logFile, File errFile) {
		return exec(baseDir, cmdArr, logFile, errFile,true,true);
	}
	
	protected int exec(File baseDir, String[] cmdArr, File logFile, File errFile, boolean failOnErroroutput, boolean failOnExitCode) {
		OutputStream logO = null;
		OutputStream errO = null;
		getLog().debug("Execute command: [" + StringUtils.join(cmdArr, "; ")+"]");
		int exitCode = -1; 
		try {
			try{
				logO = new FileIO(logFile).getBufferedOutputStream();
				errO = new FileIO(errFile).getBufferedOutputStream();
				exitCode = new RuntimeExec(baseDir,getProcessorService()).execArr(
						logO,
						errO,
						cmdArr
						);
			}finally{
				IOUtils.closeQuietly(logO);
				IOUtils.closeQuietly(errO);
			}
			String msg = "Exit code " + exitCode + " with cmd: "
				+ StringUtils.join(cmdArr, ',')
				+"! output:>"
				+logFile.getAbsolutePath()
				+"< err:>"
				+errFile.getAbsolutePath()
				+"<";
			if(exitCode != 0){
				if(failOnExitCode){
					throw new VelvetUncheckedException(
						"Problems with error code: "+ msg);
				} else {
					getLog().warn("Problems with error code: " + msg);
				}
			} else if (errFile.length() > 0) {
				if(failOnErroroutput){
					throw new VelvetUncheckedException(
							"Problems with Error output: "+ msg);
				} else {
					getLog().debug("Problems with Error output: " + msg);
				}
			}else {
				getLog().debug("Finished " + msg);
			}
		} catch (IOException e) {
			throw new VelvetUncheckedException("Problems executing command: " + StringUtils.join(cmdArr, "; "),e);
		}
		return exitCode;
	}
	
	protected abstract ProcessorService getProcessorService();

	protected File getNextFile(File dir, String prefix,String postfix){
		if(!dir.exists()){
			if(!dir.mkdirs()){
				throw new VelvetUncheckedException(
						"Not able to create File " + dir);
			}
		}
		int i = 0;
		File f = new File(dir,prefix+i+postfix);
		while(f.exists()){
			++i;
			f = new File(dir,prefix+i+postfix);
		}
		return f;
	}

	private Log getLog() {
		return log ;
	}

}